#pragma once
#include "Epoller.hpp"
#include "Socket.hpp"
#include "log.hpp"
#include "Comm.hpp"
#include <iostream>
#include <memory>
#include <functional>
#include <string>
#include <unordered_map>

// EPOLLET: ET触发模式,即边缘触发模式
uint32_t EVENT_IN = (EPOLLIN | EPOLLET);
uint32_t EVENT_OUT = (EPOLLOUT | EPOLLET);

class TcpServer;
class Connection;
using func_t = std::function<void(std::weak_ptr<Connection>)>;
using except_func = std::function<void(std::weak_ptr<Connection>)>;

class Connection
{
private:
    int _sock;
    std::string _inbuffer;  // 二进制的话用vector
    std::string _outbuffer;  
public:
    func_t _recv_cb;
    func_t _send_cb;
    except_func _except_cb;
    std::weak_ptr<TcpServer> _tcp_server_ptr;
    std::string _ip;
    uint16_t _port;

public:
    Connection(int sock) :_sock(sock)
    {}
    ~Connection() {}
    void SetHandler(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    void SetWeakPtr(std::weak_ptr<TcpServer> tcp_server_ptr)
    {
        _tcp_server_ptr = tcp_server_ptr;
    }
    const int GetFd()
    {
        return _sock;
    }
    void AppendInBuffer(const std::string &info)
    {
        _inbuffer += info;
    }
    void AppendOutBuffer(const std::string &info)
    {
        _outbuffer += info;
    }
    std::string& InBuffer()
    {
        return _inbuffer;
    }
    std::string& OutBuffer()
    {
        return _outbuffer;
    }
};

// enable_shared_from_this:可以提供返回当前对象的this对应的shared_ptr
class TcpServer: public nocopy, public std::enable_shared_from_this<TcpServer>
{
    const static int num = 64;

private:
    uint16_t _port;
    bool _quit;
    std::shared_ptr<Sock> _listensocket_ptr;
    std::shared_ptr<Epoller> _epoller_ptr;
    struct epoll_event revs[num];
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    func_t _OnMessage;
public:
    TcpServer(uint16_t port, func_t OnMessage)
        :_port(port)
        ,_quit(false)
        ,_listensocket_ptr(std::make_shared<Sock> ())
        ,_epoller_ptr(std::make_shared<Epoller> ())
        ,_OnMessage(OnMessage)
    {}
    ~TcpServer()
    {}
    void Init()
    {
        _listensocket_ptr->Socket();
        // 设置listenfd为非阻塞状态
        SetNonBlock(_listensocket_ptr->GetFd());
        _listensocket_ptr->Bind(_port);
        _listensocket_ptr->Listen();
        LOG(Info, "create listen socket success: %d", _listensocket_ptr->GetFd());
        // 设置listenfd的读、写、异常方法并且将其加入到内核中
        AddConnection(_listensocket_ptr->GetFd(), EVENT_IN, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
    }
    // 链接管理器
    void Accepter(std::weak_ptr<Connection> conn)
    {
        // 要访问weak_ptr指向的对象,可以使用lock()函数,它返回一个指向shared_ptr的shared_ptr对象.
        // 如果shared_ptr已经被销毁,则会返回一个空指针
        if (std::shared_ptr<Connection> connection = conn.lock()) {
            while (true)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int sock = ::accept(connection->GetFd(), (struct sockaddr*)&peer, &len);
                if (sock > 0) {
                    uint16_t peerport = ntohs(peer.sin_port);
                    char ipstr[128];
                    inet_ntop(AF_INET, &(peer.sin_addr.s_addr), ipstr, sizeof(ipstr));
                    LOG(Info, "get a new client, ip: %s:%d  sock: %d", ipstr, peerport, sock);
                    // 设置sock为非阻塞状态
                    SetNonBlock(sock);
                    // 设置新链接上来的sock的读、写、异常的回调方法并将其加入到内核中
                    AddConnection(sock, EVENT_IN, 
                                 std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                                 std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                                 std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                }
                else {
                    if (errno == EWOULDBLOCK) { break; }  // 说明sock的就绪内容全部读完了,errno的报错是因为阻塞了
                    else if (errno == EINTR) { continue; }  // 被其它信号异常唤醒
                    else {break;}
                }
            }
        } 
        else {
            LOG(Error, "Acceptr error, weak_ptr conn is null");
        }
    }
    void AddConnection(int sock, uint32_t event, func_t recv_cb, func_t send_cb, except_func except_cb,
                    const std::string &ip = "0.0.0.0", uint16_t port = 0)
    {
        // 1. 给sock也建立一个Connection对象,将listenfd添加到Connection中,同时listenfd和Connection对象放入_connections
        std::shared_ptr<Connection> new_connection = std::make_shared<Connection>(sock);
        // 2. 设置new_connection对象内的回调方法及其它变量
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->SetWeakPtr(shared_from_this());
        new_connection->_ip = ip;
        new_connection->_port = port;
        // 3. 将sock和new_connection对象添加到unordered_map中
        _connections.insert(std::make_pair(sock, new_connection));
        // 4. 将sock和new_connection对象添加到内核中
        _epoller_ptr->EpollUpdate(EPOLL_CTL_ADD, sock, event);

    }
    void Loop()
    {
        _quit = false;
        while (!_quit)
        {
            Dispathcer(-1);
            PrintConnection();
        }
        _quit = true;
    }
    void Dispathcer(int timeout)
    {
        int n = _epoller_ptr->EpollWait(revs, num, timeout);
        for (int i = 0; i < n; ++i)
        {
            uint32_t events = revs[i].events;
            int sock = revs[i].data.fd;
            if ((events & EPOLLIN) && IsConnectionsSafe(sock)) {
                if (_connections[sock]->_recv_cb) { _connections[sock]->_recv_cb(_connections[sock]); }
            }
            if ((events & EPOLLOUT) && IsConnectionsSafe(sock)) {
                if (_connections[sock]->_send_cb) { _connections[sock]->_send_cb(_connections[sock]); }
            }
        }
    }
    bool IsConnectionsSafe(int sock)
    {
        auto iter = _connections.find(sock);
        if (iter == _connections.end()) { return false; }
        else { return true; }
    }

    void Recver(std::weak_ptr<Connection> conn)
    {
        if (std::shared_ptr<Connection> connection = conn.lock()) {
            int sockfd = connection->GetFd();
            while (true)
            {
                char buffer[1024];
                ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);  // 由于设置了SetNonBlock，即使flag=0,也是非阻塞读取
                if (n > 0) {
                    connection->AppendInBuffer(buffer);
                }
                else if (n == 0) {
                    LOG(Info, "sockfd: %d, client: %s:%d quit...", sockfd, connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
                else {
                        if (errno == EWOULDBLOCK) { break; }  // 说明sock的就绪内容全部读完了,errno的报错是因为阻塞了
                        else if (errno == EINTR) { continue; }  // 被其它信号异常唤醒
                        else {
                            LOG(Warning, "recv error,sockfd: %d, client: %s:%d error...", sockfd, connection->_ip.c_str(), connection->_port);
                            connection->_except_cb(connection);
                            return;
                        }
                }
            }
            // 对报文进行处理
            _OnMessage(connection);
        }
        else {
            LOG(Error, "Recver error, weak_ptr conn is null");
        }
    }
    void Sender(std::weak_ptr<Connection> conn)
    {
        if (std::shared_ptr<Connection> connection = conn.lock()) {
            int sockfd = connection->GetFd();
            auto &outbuffer = connection->OutBuffer();
            while (true)
            {
                ssize_t n = send(sockfd, outbuffer.c_str(), outbuffer.size(), 0);
                if (n > 0) {
                    outbuffer.erase(0, n);
                    if (outbuffer.empty()) { break; }
                }
                else if (n == 0) {
                    return;
                }
                else {
                    if (errno == EWOULDBLOCK) { break; }  // 代表发送缓冲区已满,进入阻塞状态.跳出循环,将sockfd加入到关心事件中
                    else if (errno == EINTR) { continue; }
                    else {
                            LOG(Warning, "send error,sockfd: %d, client: %s:%d error...", sockfd, connection->_ip.c_str(), connection->_port);
                            connection->_except_cb(connection);
                            return;
                    }
                }
            } 
            // 判断是否因为sockfd阻塞跳出的循环,如果是则将该sockfd加入到关心事件中
            if (!outbuffer.empty()) {
                // 开启对写事件的关心
                EnableEvent(sockfd, true, true);
            }
            else {
                // 关闭对写事件的关心
                EnableEvent(sockfd, true, false);
            }
        }
        else {
            LOG(Error, "Acceptr error, weak_ptr conn is null");
        }
    }
    void Excepter(std::weak_ptr<Connection> conn)
    {
        if (std::shared_ptr<Connection> connection = conn.lock()) {
            int sock = connection->GetFd();
            LOG(Warning, "Except hander sockfd: %d, client: %s:%d excepter handler", sock, connection->_ip, connection->_port);
            // 1. 移除对sock的关心事件
            _epoller_ptr->EpollUpdate(EPOLL_CTL_DEL, sock, 0);
            // 2. 关闭异常的文件描述符
            close(sock);
            // 3.从unordered_map中移除
            _connections.erase(sock);
        }
        else {
            LOG(Error, "Acceptr error, weak_ptr conn is null");
        }
    }
    void EnableEvent(int sock, bool readable, bool writeable)
    {
        uint32_t events = 0;
        events |= ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0)) | EPOLLET;
        _epoller_ptr->EpollUpdate(EPOLL_CTL_MOD, sock, events);
    }
    void PrintConnection()
    {
        std::cout << "connection fd list: ";
        for (auto& connection : _connections) 
        {
            std::cout << connection.second->GetFd() << ", ";
            std::cout << "inbuffer: " << connection.second->InBuffer().c_str() << "     ";
        }
        std::cout << std::endl;
    }
};